package com.ecosoft.config;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class ConfigContainer {
	private final static GroupMarker defaultGroupMarker = new GroupMarker("__defaultGroupMarker");
	private final static ConfigContainer instance = new ConfigContainer();
	private static final Pattern pattern = Pattern.compile("\\$\\{([^}]*)\\}");
	//private static List<IConfig> configs = new ArrayList<IConfig>();
	private static Map<GroupMarker,List<IConfig>> groupMarkers = new HashMap<GroupMarker,List<IConfig>>();
    private ConfigContainer(){}
    private boolean init = false;
    private String configDir;
    public void setConfigDir(String configDir)
    {
    	this.configDir = configDir;
    }
    public synchronized void  initContainer()
    {
    	if(!init)
    	{
    		new ProviderNotifier(configDir).notifyProvider();
    		init = true;
    	}
    }
    public static ConfigContainer getInstance()
    {
    	return instance;
    }
    /**
     * 注册配置实体，如果后注册的实体和前面注册的实体含有相同的属性名，那么当用户调用getProperty()方法的时候，<br>
     * 返回的是后面注册实体的属性值。
     * @param config 注册实体
     */
    public static synchronized void register(IConfig config)
    {
    	register(defaultGroupMarker,config);
    }
    /**
     * 注册配置实体，如果后注册的实体和前面注册的实体含有相同的属性名，那么当用户调用getProperty()方法的时候，<br>
     * 返回的是后面注册实体的属性值。
     * @param config 注册实体
     */
    public static synchronized void register(GroupMarker groupMarker,IConfig config)
    {
    	if(groupMarker == null)
    	{
    		groupMarker = defaultGroupMarker;
    	}
    	List<IConfig> configs = groupMarkers.get(groupMarker);
    	if(configs ==null)
    	{
    		configs = new ArrayList<IConfig>();
    		groupMarkers.put(groupMarker, configs);
    	}
    	configs.add(config);
    }
    public String getProperty(GroupMarker groupMarker,String key)
    {
    	if(groupMarker == null)
    	{
    		groupMarker = defaultGroupMarker;
    	}
        String value = getValue(groupMarker, key);
    	if(value!=null&&!defaultGroupMarker.equals(groupMarker))
    	{
    		value = replace(defaultGroupMarker,value);
    	}
    	return value;
    }
    private String getValue(GroupMarker groupMarker,String key)
    {
    	List<IConfig> configs = groupMarkers.get(groupMarker);
    	String value = null;
    	if(configs!=null)
    	{
    		for(IConfig config :configs)
    		{
    			value = config.getProperty(key);
    			if(value!=null)
    			{
    				value = replace(groupMarker,value);
    				break;
    			}
    		}
    	}
    	return value;
    }
    public void removeProperty(GroupMarker groupMarker,String key)
    {
    	List<IConfig> configs = groupMarkers.get(groupMarker);
    	if(configs!=null)
    	{
    		for(IConfig config:configs)
    		{
    			if(config.containsKey(key))
    			{
    				config.removeProperty(key);
    			}
    		}
    	}
    }
    public void removeProperty(String key)
    {
    	this.removeProperty(defaultGroupMarker, key);
    }
    private String replace(GroupMarker groupMarker,String input)
    {
    	Matcher matcher  = pattern.matcher(input);
    	StringBuffer value = new StringBuffer();
    	while(matcher.find())
    	{
    		String key = matcher.group(1);
    		String keyValue = this.getProperty(groupMarker, key);
    		if(keyValue!=null)
    		{
    			matcher.appendReplacement(value, keyValue); 
    		}else
    		{
    			matcher.appendReplacement(value, key);
    		}
    	}
    	matcher.appendTail(value);
		return value.toString();
    }
    public String getProperty(String key)
    {
    	return this.getProperty(defaultGroupMarker, key);
    }
    public Map<String, String> getPropertyStartWith(GroupMarker groupMarker,String prefix)
    {
    	List<IConfig> configs = groupMarkers.get(groupMarker);
    	Map<String,String> map = new HashMap<String,String>();
    	if(configs!=null)
    	{
    		for(IConfig config:configs)
    		{
    			Map<String,String> configMap = config.getPropertyStartWith(prefix);
    			if(configMap!=null)
        		{
        			for(String key:configMap.keySet())
        	    	{
        	    		map.put(key, getProperty(groupMarker,key));
        	    	}
        		}
    		}
    	}
    	return map;
    }
    public Map<String, String> getPropertyStartWith(String prefix)
    {
    	return this.getPropertyStartWith(defaultGroupMarker, prefix);
    }
    public List<String> propertyNamesList()
    {
    	return this.propertyNamesList(defaultGroupMarker);
    }
    public List<String> propertyNamesList(GroupMarker groupMarker)
    {
    	List<IConfig> configs = groupMarkers.get(groupMarker);
    	List<String> names = new ArrayList<String>();
    	if(configs!=null)
    	{
    		for(IConfig config:configs)
    		{
    			names.addAll(config.propertyNamesList());
    		}
    	}
    	return names;
    }
    public boolean containsKey(GroupMarker groupMarker,String key)
    {
    	List<IConfig> configs = groupMarkers.get(groupMarker);
    	if(configs!=null)
    	{
    		for(IConfig config:configs)
    		{
    			if(config.containsKey(key))
    			{
    				return true;
    			}
    		}
    	}
    	return false;
    }
    public boolean containsKey(String key) 
    {
		return this.containsKey(defaultGroupMarker, key);
	}
    public String getProperty(String key, String defaultValue)
    {
    	return this.getProperty(defaultGroupMarker, key , defaultValue);
    }
    public String getProperty(GroupMarker groupMarker,String key, String defaultValue)
    {
    	String value = getProperty(groupMarker,key);
    	if(value == null)
    	{
    		return defaultValue;
    	}
    	return value;
    }
    public int getProperty(GroupMarker groupMarker,String key, int defaultValue)
    {
    	String value = getProperty(groupMarker,key);
    	if (value != null)
		{
			return Integer.parseInt(value);
		}
		return defaultValue;
    }
	public int getProperty(String key, int defaultValue) 
	{
		return this.getProperty(defaultGroupMarker, key,defaultValue);
	}
	public boolean getProperty(GroupMarker groupMarker,String key, boolean defaultValue)
	{
		String value = getProperty(groupMarker,key);
    	if (value != null)
		{
			return Boolean.valueOf(value);
		}
		return defaultValue;
	}
	public boolean getProperty(String key, boolean defaultValue) 
	{
		return this.getProperty(defaultGroupMarker,key,defaultValue);
	}
	public void updateProperty(GroupMarker groupMarker,String key, String value)
	{
		List<IConfig> configs = groupMarkers.get(groupMarker);
		for(IConfig config:configs)
		{
			if(config.containsKey(key))
			{
				config.updateProperty(key, value);
			}
		}
	}
	public void updateProperty(String key, String value)
	{
		this.updateProperty(defaultGroupMarker, key, value);
	}
}
